#include "Fase_DBG.hpp"

namespace bp
{

	using namespace std;  

	Fase_DBG::Fase_DBG(const char* id, configurador* config) :
        fase(id, config),
		m_ejecutandose(true),
		m_fondo(0),
		m_enemigo(0),
		GetTime(0)

	{	

	}

	bool Fase_DBG::Inicializar()
	{
		SDL_initFramerate ( &m_manejadorImgPorSeg );
		SDL_setFramerate ( &m_manejadorImgPorSeg, m_configurador->Imagenes_por_Segundo());
		m_configurador->ObtenerActor()->resetTeclas();	
		m_configurador->ObtenerActor()->resetRepetTeclas();

		m_fondo = Imagen::Cargar(Paths.ObtieneRuta("FONDO_FASE_DBG"));
		if (m_fondo == 0) return false;

		// DEBUG
		if ((m_tx_Debg.CargaFuente(Paths.ObtieneRuta("FUENTES_FASE_INTRO"), 14)) == false) return false;
		SDL_Color colorTitulo = {72, 61, 139, 0};
		SDL_Color colorFondoTitulo = {255, 255, 255, 0};
		m_tx_Debg.PonerColor ( colorTitulo );
		m_tx_Debg.PonerColorFondo ( colorFondoTitulo );	
		if ((m_tx_Debg2.CargaFuente(Paths.ObtieneRuta("FUENTES_FASE_INTRO"), 14)) == false) return false;
		m_tx_Debg2.PonerColor ( colorTitulo );
		m_tx_Debg2.PonerColorFondo ( colorFondoTitulo );		
		// DEBUG

		SDL_Rect PosInicial = {600, 400, 0, 0};		
		Color_t colorTransp = {68, 9, 123};
		m_enemigo = new ElFuler(PosInicial, perfilIzq, colorTransp, Paths.ObtieneRuta("FULLER_PERFIL_DER"), Paths.ObtieneRuta("FULLER_PERFIL_IZQ"));				

		fx[0].Cargar(Paths.ObtieneRuta("FULLER_SONIDO_MANO"));
		fx[1].Cargar(Paths.ObtieneRuta("FULLER_SONIDO_PATADA"));
		
		memset(tiempoEntreMovs, 0, sizeof(tiempoEntreMovs[0]) * TipoMov_LEN);
		return true;
	}

	void Fase_DBG::Limpiar()
	{
		m_configurador->ObtenerActor()->resetTeclas();
	}


	Fase_DBG::~Fase_DBG(void)
	{
		Limpiar();
		if (m_enemigo) delete m_enemigo;
		if (m_fondo) SDL_FreeSurface(m_fondo);
		for(vector<Proyectil*>::iterator it = m_proyectiles.begin(); it < m_proyectiles.end(); it++)
			if (*it) delete *it;
	}

	void Fase_DBG::Salir()
	{
		m_ejecutandose = false;
	}


	bool Fase_DBG::Ejecutar()
	{
		if ((Inicializar()) == false) return false;
		if ((Iteracion()) == false) return false;

		return true;
	}
	
	bool Fase_DBG::Iteracion()
	{
		while ( m_ejecutandose )
		{
			// Que teclas han sido pulsadas
			while ( SDL_PollEvent ( &m_evento ) ) OnEvent ( &m_evento );			
			// Se analizan los movientos del Usuario o Heroe
			GestionMovs();
			// Se analizan los movimintos de ambos jugadores su entorno y la IA actua en consecuencia
			GestionMovsAI(m_configurador->Escenario(), m_configurador->ObtenerActor(), m_enemigo );
			// Se gestionan los efectos especiales 
			GestFXs(m_configurador->ObtenerActor(), m_enemigo );
			// Se actuliza la pantalla
			if ((Dibujar()) == false) return false;
			// Se limpia las teclas usadas
			Limpiar();
			GetTime = SDL_getTime(&m_manejadorImgPorSeg);
			// Se gestionan los Fotogramas por Segundo
			SDL_framerateDelay ( &m_manejadorImgPorSeg );
		}

		return true;

	}
	
	inline void Fase_DBG::OnKeyDown(SDLKey sym, SDLMod , Uint16 )
	{
		//tio << "KEY PRESS : " << conv::SDLKeyToString(sym) << "\t";
		m_configurador->ObtenerActor()->teclas(sym)->Press = true;  
	}

	inline void Fase_DBG::OnKeyUp(SDLKey sym, SDLMod , Uint16 )
	{
		//tio << "KEY UNPRESS : " << conv::SDLKeyToString(sym) << "\t";
		m_configurador->ObtenerActor()->teclas(sym)->UnPress = true;  
	}

	inline void Fase_DBG::Pgdb(SDLKey sym, const char* atr, bool val)
	{
		m_io << "[" << sym << "]" << "." << atr << " = " << val << " "; 
	}

	
	void Fase_DBG::GestFXs(actor* heroe, actor* enemigo)
	{
		fx[0].Parar();
		fx[1].Parar();
		if (heroe->mov_stat()->en_curso == golpeo_mano || heroe->mov_stat()->en_curso == golpe_mano_alto ||
            heroe->mov_stat()->en_curso == golpeo_mano_bajo)
			fx[0].Sonar();					
		if (heroe->mov_stat()->en_curso == patada || heroe->mov_stat()->en_curso == patada_circular ||
            heroe->mov_stat()->en_curso == patada_baja)
			fx[1].Sonar();
        
		if (enemigo->mov_stat()->en_curso == golpeo_mano || enemigo->mov_stat()->en_curso == golpe_mano_alto ||
            enemigo->mov_stat()->en_curso == golpeo_mano_bajo)
			fx[0].Sonar();
		if (enemigo->mov_stat()->en_curso == patada || enemigo->mov_stat()->en_curso == patada_circular ||
            enemigo->mov_stat()->en_curso == patada_baja)
			fx[1].Sonar();
	}

    /*
     Este metodo solo se encarga de gestionar los movimientos del ENEMIGO o IA
     , pero en el caso de que el heroe resulte golpeado se modificara la eleccion
     del jugador por un movimiento de recepcion de golpe de nivel en funcion del
     golpe recibido.
     
     */
	void Fase_DBG::GestionMovsAI(SDL_Surface* ,actor* heroe, actor* enemigo)
	{		
		// DEBUG	
		m_io2.str(" ");
		m_io2 << "TIME : "  << GetTime << " seg  # ";
		m_io2 << "COLISION - MOV HEROE: " << TipoMovToString[heroe->mov_stat()->en_curso] << " MOV ENEMIGO : " << TipoMovToString[enemigo->mov_stat()->en_curso];
		// DEBUG

		// Se recupera los datos de posicion del movimiento actual de los actores
		ty_s_conf_mov* mov_heroe = heroe->mov_conf(make_pair(heroe->mov_stat()->en_curso, heroe->mov_stat()->sentido));
		ty_s_conf_mov* mov_enemigo = enemigo->mov_conf(make_pair(enemigo->mov_stat()->en_curso, enemigo->mov_stat()->sentido));

        
        if (heroe->mov_stat()->en_curso == recep_golpe_N1 || heroe->mov_stat()->en_curso == recep_golpe_N2 ||
            heroe->mov_stat()->en_curso == recep_golpe_N3 || heroe->mov_stat()->en_curso == patada_helicop ||
            heroe->mov_stat()->en_curso == salto_largo ||
            enemigo->mov_stat()->en_curso == salto_largo ||
            enemigo->mov_stat()->en_curso == recep_golpe_N1 || enemigo->mov_stat()->en_curso == recep_golpe_N2 ||
            enemigo->mov_stat()->en_curso == recep_golpe_N3 || enemigo->mov_stat()->en_curso == patada_helicop
            )
			return;
        
		// Detectar el sentido del oponente y ajustar ambos
		int32_t sentido = (enemigo->mov_stat()->pos_actual.x < heroe->mov_stat()->pos_actual.x) ? perfilDer : perfilIzq;	
		enemigo->mov_stat()->sentido = (sentido != enemigo->mov_stat()->sentido) ? sentido : enemigo->mov_stat()->sentido;
        heroe->mov_stat()->sentido = (enemigo->mov_stat()->sentido == perfilIzq) ? perfilDer : perfilIzq;

		// Distancia al oponente
		int32_t distancia = (enemigo->mov_stat()->pos_actual.x > heroe->mov_stat()->pos_actual.x) ?
							enemigo->mov_stat()->pos_actual.x - heroe->mov_stat()->pos_actual.x : 
							heroe->mov_stat()->pos_actual.x - enemigo->mov_stat()->pos_actual.x;
		

		// AVANCE Y RETORNO
		int32_t enemigo_avance	= (sentido == perfilIzq) ? retorno	: avance;
		int32_t enemigo_retorno = (sentido == perfilIzq) ? avance	: retorno;

		// Detectar colision. Estamos a distacia como para atacar con golpes cortos (patadas, golpe_mano) ?
        int32_t quienGolpeoPrimero = TABLAS;
		if (EscanerColisiones(m_configurador->Escenario(), m_configurador->ObtenerActor(), mov_heroe, enemigo, mov_enemigo, quienGolpeoPrimero))
		{	// SI
            if (quienGolpeoPrimero == HEROE)
            {
                int32_t movRecep = 0;
                if (heroe->mov_stat()->en_curso == golpeo_mano || heroe->mov_stat()->en_curso == patada
                    || heroe->mov_stat()->en_curso == patada_baja || heroe->mov_stat()->en_curso == golpeo_mano_bajo
                    || heroe->mov_stat()->en_curso == golpe_mano_alto )
                    movRecep = recep_golpe_N1;
                
                else if (heroe->mov_stat()->en_curso == patada_circular || heroe->mov_stat()->en_curso == patada_helicop)
                    movRecep = recep_golpe_N2;
                
                else if (heroe->mov_stat()->en_curso == bola_fuego)
                    movRecep = recep_golpe_N3;
                
                tiempoEntreMovs[movRecep] = GetTime;
                enemigo->ActivaTipoMovimiento(movRecep, sentido);
                enemigo->mov_stat()->repeticion[movRecep] = false;
                enemigo->SetDelay(0);
            }
            else if (quienGolpeoPrimero == ENEMIGO)
            {
                int32_t movRecep = 0;
                if (enemigo->mov_stat()->en_curso == golpeo_mano || enemigo->mov_stat()->en_curso == patada
                    || enemigo->mov_stat()->en_curso == patada_baja || enemigo->mov_stat()->en_curso == golpeo_mano_bajo
                    || enemigo->mov_stat()->en_curso == golpe_mano_alto )
                    movRecep = recep_golpe_N1;
                
                else if (enemigo->mov_stat()->en_curso == patada_circular || enemigo->mov_stat()->en_curso == patada_helicop)
                    movRecep = recep_golpe_N2;
                
                else if (enemigo->mov_stat()->en_curso == bola_fuego)
                    movRecep = recep_golpe_N3;
                
                if (
                    heroe->mov_stat()->en_curso != salto_largo &&
                    heroe->mov_stat()->en_curso != salto_arriba &&
                    heroe->mov_stat()->en_curso != golpe_mano_alto &&
                    ( movRecep == recep_golpe_N1 || movRecep == recep_golpe_N2 || movRecep == recep_golpe_N3 )
                    )
                {
                    tiempoEntreMovs[movRecep] = GetTime;
                    heroe->ActivaTipoMovimiento(movRecep, heroe->mov_stat()->sentido);
                    heroe->mov_stat()->repeticion[movRecep] = false;
                    heroe->SetDelay(0);
                    return;
                }
                
                /* 
                    Movimiento siguiente seleccionado aleatoriamente, a futuro seleccionar en funcion de
                    condiciones y estado del sistema
                 */
                int32_t mov = rand() % 4 + 1;
                if (enemigo->mov_stat()->en_curso != mov &&
                    (heroe->mov_stat()->en_curso != recep_golpe_N1 &&
                     heroe->mov_stat()->en_curso != recep_golpe_N2 &&
                     heroe->mov_stat()->en_curso != recep_golpe_N3)
                    )
                {
                    tiempoEntreMovs[mov] = GetTime;
                    enemigo->ActivaTipoMovimiento(mov, sentido);
                    enemigo->mov_stat()->repeticion[mov] = false;
                    enemigo->SetDelay(0);
                }
            }

		}
        /*
         * Si no hay colisiones cada vez que termina el ciclo de un movimiento entra aqui
         */
		else if (enemigo->mov_stat()->en_curso == descanso)
		{
            int32_t distancia_lim = (enemigo->mov_stat()->vida > 50) ? 100 : 350;
			if( distancia > distancia_lim)
			{
				if ( ((GetTime - tiempoEntreMovs[bola_fuego]) > 20 || time == 0) && distancia > 250)
				{					
					tiempoEntreMovs[bola_fuego] = GetTime;
					enemigo->ActivaTipoMovimiento(bola_fuego, sentido);
					enemigo->mov_stat()->repeticion[bola_fuego] = false;
					enemigo->SetDelay(0);
				}
				else
				{
                    if (distancia > 250)
                    {
                        tiempoEntreMovs[salto_largo] = GetTime;
                        enemigo->ActivaTipoMovimiento(salto_largo, sentido);
                        enemigo->mov_stat()->repeticion[salto_largo] = false;
                        enemigo->SetDelay(0);
                    }
                    else
                    {
                        tiempoEntreMovs[enemigo_avance] = GetTime;
                        enemigo->ActivaTipoMovimiento(enemigo_avance, sentido);
                        enemigo->mov_stat()->repeticion[enemigo_avance] = false;
                        enemigo->SetDelay(0);
                    }
				}
			}
			else  
			{
                if (heroe->mov_stat()->en_curso == descanso)
                {
                    distancia_lim = 100;
                    if (distancia > distancia_lim)
                    {
                        if ( ((GetTime - tiempoEntreMovs[bola_fuego]) > 20 || time == 0) && distancia > 450)
                        {
                            tiempoEntreMovs[bola_fuego] = GetTime;
                            enemigo->ActivaTipoMovimiento(bola_fuego, sentido);
                            enemigo->mov_stat()->repeticion[bola_fuego] = false;
                            enemigo->SetDelay(0);
                        }
                        else 
                        {
                            tiempoEntreMovs[enemigo_avance] = GetTime;
                            enemigo->ActivaTipoMovimiento(enemigo_avance, sentido);
                            enemigo->mov_stat()->repeticion[enemigo_avance] = false;
                            enemigo->SetDelay(0);
                        }
                    }
                    else
                    {
                        int32_t mov = rand() % 4 + 1;
                        if (enemigo->mov_stat()->en_curso != mov)
                        {
                            tiempoEntreMovs[mov] = GetTime;
                            enemigo->ActivaTipoMovimiento(mov, sentido);
                            enemigo->mov_stat()->repeticion[mov] = false;
                            enemigo->SetDelay(0);
                        }
                    }
                }
                else
                {
                    tiempoEntreMovs[enemigo_retorno] = GetTime;
                    enemigo->ActivaTipoMovimiento(enemigo_retorno, sentido);
                    enemigo->mov_stat()->repeticion[enemigo_retorno] = false;
                    enemigo->SetDelay(0);
                }
			}
		} 	
      
	}

	bool Fase_DBG::EscanerColisiones(SDL_Surface* , actor* heroe, ty_s_conf_mov* mov_heroe, actor* enemigo, ty_s_conf_mov* mov_enemigo, int32_t& quienGolpeoPrimero)
	{   
		SDL_Rect rect_heroe = { 0, 0, 0, 0};
		SDL_Rect rect_enemigo = { 0, 0, 0, 0};
		ObtAreaPersonajes(heroe, mov_heroe, enemigo, mov_enemigo, rect_heroe, rect_enemigo);
		static int32_t delay = 0;
        delay = (delay == 6)? 0: delay + 1;
		if ((Colisiones::CollideBoundingBox(rect_heroe, rect_enemigo)) == true && delay == 0)
		{
			// Se actualiza la energia de cada contrincante en funcion de con que y quien golpea
			GestEnergia(heroe, mov_heroe, enemigo, mov_enemigo, rect_heroe, rect_enemigo, quienGolpeoPrimero);
			return true;	
		}
		return false;
	}

	void Fase_DBG::ObtAreaPersonajes(actor* heroe, ty_s_conf_mov* mov_heroe, actor* enemigo, ty_s_conf_mov* mov_enemigo, SDL_Rect& rect_heroe, SDL_Rect& rect_enemigo)
	{
		size_t heroe_index_pos = (heroe->mov_stat()->ulti_sec == mov_heroe->numero) ? heroe->mov_stat()->ulti_sec-1 : heroe->mov_stat()->ulti_sec;
		size_t enemigo_index_pos = (enemigo->mov_stat()->ulti_sec == mov_enemigo->numero) ? enemigo->mov_stat()->ulti_sec-1 : enemigo->mov_stat()->ulti_sec;    		
		
		// HEROE AREA
		rect_heroe.x = heroe->mov_stat()->pos_actual.x; 
		rect_heroe.y = heroe->mov_stat()->pos_actual.y;
		rect_heroe.w = mov_heroe->sec_img.at(heroe_index_pos).w;
		rect_heroe.h = mov_heroe->sec_img.at(heroe_index_pos).h;
		
		// ENEMIGO AREA		
		rect_enemigo.x = enemigo->mov_stat()->pos_actual.x; 
		rect_enemigo.y = enemigo->mov_stat()->pos_actual.y;
		rect_enemigo.w = mov_enemigo->sec_img.at(enemigo_index_pos).w;
		rect_enemigo.h = mov_enemigo->sec_img.at(enemigo_index_pos).h;
	}

	void Fase_DBG::GestEnergia(actor* heroe, ty_s_conf_mov* mov_heroe, actor* enemigo, ty_s_conf_mov* mov_enemigo, SDL_Rect rect_heroe, SDL_Rect rect_enemigo, int32_t& quienGolpeoPrimero)
	{
		if (rect_heroe.w > rect_enemigo.w)
		{
			enemigo->mov_stat()->vida -= mov_heroe->fuerza;
            quienGolpeoPrimero = HEROE;
		}
		else if (rect_heroe.w < rect_enemigo.w)
		{
			heroe->mov_stat()->vida -= mov_enemigo->fuerza;
            quienGolpeoPrimero = ENEMIGO;
		}
		else if (rect_heroe.w == rect_enemigo.w)
		{
            quienGolpeoPrimero = TABLAS;
		}
	}


    void Fase_DBG::Camara2(SDL_Surface* ImagenDestino, SDL_Surface* ImagenOrigen)
    {
        
        int32_t actor_x = m_configurador->ObtenerActor()->mov_stat()->pos_actual.x;
        int32_t enemigo_x = m_enemigo->mov_stat()->pos_actual.x;
        //int32_t pantalla_ancho = m_configurador->Pantalla_Ancho();
        //int32_t pantalla_ancho_total = ImagenOrigen->w;
        int32_t distancia_entre_actores = (actor_x < enemigo_x)? actor_x - enemigo_x : enemigo_x - actor_x;
        int32_t margen = distancia_entre_actores / 2;

        if (actor_x < enemigo_x)
            if (actor_x - margen < 0)
                Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, (actor_x - margen) * -1 , 0, ImagenDestino->w,  ImagenDestino->h );        
            else
            {
                if (actor_x - margen < 30)
                    Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, actor_x - margen , 0, ImagenDestino->w,  ImagenDestino->h );
                else
                    Imagen::Dibujar(ImagenDestino, ImagenOrigen);
            }
        else
        {
            if (enemigo_x - margen < 0)
                Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, (enemigo_x - margen) * -1 , 0, ImagenDestino->w,  ImagenDestino->h );
            else
            {
                if (enemigo_x - margen < 30)
                    Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, enemigo_x - margen , 0, ImagenDestino->w,  ImagenDestino->h );
                else
                    Imagen::Dibujar(ImagenDestino, ImagenOrigen);
            }
        }
        	     
    }
    
	void Fase_DBG::Camara(SDL_Surface* ImagenDestino, SDL_Surface* ImagenOrigen)
	{
		int32_t margen = 150;
		static int32_t despla_x = (ImagenOrigen->w - ImagenDestino->w)/2, despla = 15, delay = 3;  

		if ( m_configurador->ObtenerActor()->mov_stat()->repeticion[avance] == true && delay-- == 0)
		{
			delay = 5;
			SDL_Rect pos = m_configurador->ObtenerActor()->mov_stat()->pos_actual;
			if (pos.x > (ImagenDestino->w - (margen+100)) && pos.x < ImagenDestino->w)
			{
				if ((despla_x + despla) >= ImagenDestino->w)	  
					Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );	  
				else
				{
					despla_x += despla;
					Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );
				}
			}
			else	
				Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );		
		}
		else if (m_configurador->ObtenerActor()->mov_stat()->repeticion[retorno] == true && delay-- == 0)
		{
			delay = 5;
			SDL_Rect pos = m_configurador->ObtenerActor()->mov_stat()->pos_actual;
			if (pos.x > 0 && pos.x < margen)
			{
				if ((despla_x - despla) <= 0)	  
					Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );	 
				else
				{
					despla_x -= despla;
					Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );
				}
			}
			else	
				Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );		
		}
		else  		
			Imagen::Dibujar(ImagenDestino, ImagenOrigen, 0, 0, despla_x, 0, ImagenDestino->w,  ImagenDestino->h );    
	}



	bool Fase_DBG::Dibujar()
	{  
		// Limpia la imagen
		Imagen::LimpiarImagen(m_configurador->Escenario());    
		// Dibuja el escenario de fondo
        Camara2(m_configurador->Escenario(), m_fondo);
		//Camara(m_configurador->Escenario(), m_fondo);
		// Dibuja al ENEMIGO
		m_enemigo->Dibujar(m_configurador->Escenario(), m_enemigo->mov_stat()->en_curso);
		// Dibuja al HEROE o JUGADOR
		m_configurador->ObtenerActor()->Dibujar(m_configurador->Escenario(), m_configurador->ObtenerActor()->mov_stat()->en_curso);  

		// DEBUG
		m_io.str(" ");
		SDL_Surface* TextoImagen = 0, * TextoImagen2 = 0;

		m_io << " HEROE : " <<  m_configurador->ObtenerActor()->mov_stat()->vida << " ENEMIGO : " << m_enemigo->mov_stat()->vida;
		TextoImagen = m_tx_Debg.Dibujar(m_io.str().c_str());
		Imagen::Dibujar (m_configurador->Escenario(), TextoImagen, 380, 10);

		TextoImagen2 = m_tx_Debg2.Dibujar(m_io2.str().c_str());
		Imagen::Dibujar (m_configurador->Escenario(), TextoImagen2, 10, 50);

		if (TextoImagen) SDL_FreeSurface(TextoImagen);
		if (TextoImagen2) SDL_FreeSurface(TextoImagen2);
		// DEBUG

		SDL_Flip ( m_configurador->Escenario() );
		return true;
	}

} // namespace bp
